//
// Created by 77873 on 2020/10/12 0012.
//


#include "AudioDecodec.h"

AudioDecodec::AudioDecodec(PlayStatus *ps, CallBackToJava *cbj, int sampleRate) {
    this->playStatus = ps;
    this->callBackToJava = cbj;
    this->sample_rate = sampleRate;
    audioDataQueue = new DataQueue(playStatus);
    buffer = (uint8_t *) (av_malloc(sample_rate * 2 * 2));

    pthread_mutex_init(&codecMutex, NULL);
}

AudioDecodec::~AudioDecodec() {
    pthread_mutex_destroy(&codecMutex);
}


void *decodePlay(void *data) {
    AudioDecodec *audioDecodec = static_cast<AudioDecodec *>(data);
    //初始化openSL ES
    audioDecodec->initOpenSl();
//    pthread_exit(&audioDecodec->threadPlay);
    return 0;
}

void AudioDecodec::startPlay() {
    if(playStatus!=NULL&&!playStatus->isExit){
        pthread_create(&threadPlay, NULL, decodePlay, this);
    }

}

void simpleBufferQueueCallback(SLAndroidSimpleBufferQueueItf bf, void *context) {
//    LOGE("simpleBufferQueueCallback start");

    AudioDecodec *audioDecodec = static_cast<AudioDecodec *>(context);

    if (audioDecodec != NULL) {



            int buffersize = audioDecodec->getPcmData();
//        LOGE("bufferSize %d ", buffersize);


            if (buffersize > 0) {
                audioDecodec->clock += buffersize / ((double)(audioDecodec->sample_rate * 2 * 2));
                if(audioDecodec->clock - audioDecodec->last_time >= 0.1)
                {
                    audioDecodec->last_time = audioDecodec->clock;
                    //回调应用层
                    audioDecodec->callBackToJava->onCallTimeInfo(CHILD_THREAD, audioDecodec->clock, audioDecodec->duration);
                }

//                LOGE("bufferSize is %d", buffersize);
//                LOGE("调用opensl 播放 simpleBufferQueueItf->Enqueue");
                (*audioDecodec->simpleBufferQueueItf)->Enqueue(audioDecodec->simpleBufferQueueItf,
                                                               audioDecodec->buffer, buffersize);
        }
    } else {
        LOGE("audioEncodec is null");
    }

//    LOGE("simpleBufferQueueCallback  finished");

}

/**
 * 1、 创建接口对象
 *   2、设置混音器
 *   3、创建播放器（录音器）
 *   4、设置缓冲队列和回调函数
 *   5、设置播放状态
 *   6、启动回调函数
 */
void AudioDecodec::initOpenSl() {
    LOGE("initOpenSL ES start");

    //获取返回值 (用来判断操作成功或否)
    SLresult sLresult;
    //step1 创建并初始化引擎对象
    sLresult = slCreateEngine(&slObjectItf, 0, NULL, 0, NULL, NULL);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("slCreateEngine failed");
    }
    sLresult = (*slObjectItf)->Realize(slObjectItf, SL_BOOLEAN_FALSE);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("engineObject Realize failed");
    }
    sLresult = (*slObjectItf)->GetInterface(slObjectItf, SL_IID_ENGINE, &slEngineItf);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("engineObject GetInterface SL_IID_ENGINE  failed");
    }
    //step2 设置混音器  并将环境混响指定为非必需接口
    const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
    const SLboolean req[1] = {SL_BOOLEAN_FALSE};

    sLresult = (*slEngineItf)->CreateOutputMix(slEngineItf, &outputMixObject, 1, ids, req);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("slEngineItf CreateOutputMix failed");
    }
    sLresult = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("outputMix relize failed");
    }

    sLresult = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
                                                &slEnvironmentalReverbItf);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("outputMixObject GetInterface slEnvironmentalReverbItf failed");
    }
    sLresult = (*slEnvironmentalReverbItf)->SetEnvironmentalReverbProperties(
            slEnvironmentalReverbItf, &reverbSettings
    );
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("SetEnvironmentalReverbProperties failed");
    }
    //step3 创建音频播放器

    //(1)配置音频源
    SLDataLocator_AndroidBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
    SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 2,
                                   static_cast<SLuint32>(getCurrentSampleRateForOpensles(
                                           sample_rate)),
                                   SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
                                   SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
                                   SL_BYTEORDER_LITTLEENDIAN};

    SLDataSource audioSrc = {&loc_bufq, &format_pcm};
    //(2)配置音频接收器
    SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    SLDataSink audioSnk = {&loc_outmix, NULL};


    const SLInterfaceID pInterfaceIds[4] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_MUTESOLO,
                                            SL_IID_PLAYBACKRATE};
    const SLboolean pInterfaceRequired[4] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
                                             SL_BOOLEAN_TRUE};

    sLresult = (*slEngineItf)->CreateAudioPlayer(slEngineItf, &audioPlayerObject,
                                                 &audioSrc, &audioSnk,
                                                 4, pInterfaceIds, pInterfaceRequired);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("slEngineItf CreateAudioPlayer failed");
    }

    //realize the player
    sLresult = (*audioPlayerObject)->Realize(audioPlayerObject, SL_BOOLEAN_FALSE);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("audioPlayer Realize failed");
    }

    // get the play interface
    sLresult = (*audioPlayerObject)->GetInterface(audioPlayerObject, SL_IID_PLAY, &audioPlayItf);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("get the play interface  on error")
        return;
    }

    //get the buffer queue interface
    sLresult = (*audioPlayerObject)->GetInterface(audioPlayerObject, SL_IID_BUFFERQUEUE,
                                                  &simpleBufferQueueItf);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("Audio player GetInterface simpleBufferQueueItf failed");
    }

    //获取声道
    sLresult = (*audioPlayerObject)->GetInterface(audioPlayerObject, SL_IID_MUTESOLO,&slMuteSoloItf);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("audioPlayer GetInterface slMuteSoloItf failed");
    }
    //获取声音大小

    sLresult = (*audioPlayerObject)->GetInterface(audioPlayerObject, SL_IID_VOLUME, &slVolumeItf);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("audioPlayer GetInterface slVolumeItf failed");
    }

    setVolume(volumePercent);
    setMute(mute);

    // register callback on the buffer queue

    sLresult = (*simpleBufferQueueItf)->RegisterCallback(simpleBufferQueueItf,
                                                         simpleBufferQueueCallback, this);

    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("simpleBufferQueueItf RegisterCallback failed");
    }

    /**
     *
     * 设置播放状态
     */
    sLresult = (*audioPlayItf)->SetPlayState(audioPlayItf, SL_PLAYSTATE_PLAYING);
    if (sLresult != SL_RESULT_SUCCESS) {
        LOGE("SetPlayState  on error")
        return;
    }

    LOGE("init opensl  success ");
    /**
       * 回调
       */
    simpleBufferQueueCallback(simpleBufferQueueItf, this);
}


void AudioDecodec::release() {
    
    if(NULL!=audioDataQueue){
        audioDataQueue->noticeQueue();
    }

    pthread_join(threadPlay,NULL);


    /**
     * 释放音频数据队列
     */
    if (NULL != audioDataQueue) {
        delete (audioDataQueue);
        audioDataQueue = NULL;
    }

    /**
     * 释放opensl es
     */
    if (NULL != audioPlayerObject) {
        (*audioPlayerObject)->Destroy(audioPlayerObject);
        audioPlayerObject = NULL;
        audioPlayItf = NULL;
        slMuteSoloItf = NULL;
        slVolumeItf = NULL;
        simpleBufferQueueItf = NULL;
    }
    if (NULL != outputMixObject) {
        (*outputMixObject)->Destroy(outputMixObject);
        outputMixObject = NULL;
        slEnvironmentalReverbItf = NULL;
    }
    if (NULL != slObjectItf) {
        (*slObjectItf)->Destroy(slObjectItf);
        slEngineItf = NULL;
        slObjectItf = NULL;
    }

    /**
     * 释放buffer  buffer 是我们自己申请的堆空间，需要手动释放
     */
    if (NULL != buffer) {
        free(buffer);
        buffer = NULL;
    }

    /**
     * 释放解码器上下文
     */

    if (NULL != audioCodecContex) {
        avcodec_close(audioCodecContex);
        avcodec_free_context(&audioCodecContex);
        audioCodecContex = NULL;
    }

    /**
     * 释放 playstatus 与callbackToJava
     */
    if (NULL != playStatus) {
        playStatus = NULL;
    }
    if (NULL != callBackToJava) {
        callBackToJava = NULL;
    }


}

int AudioDecodec::getPcmData() {
//    LOGE("audioCodec getPcmData()");
    //循环取出
    data_size=0;
    while (NULL != playStatus && !playStatus->isExit) {
        if (playStatus->isSeek) {
            LOGE("AudioDecodec::getPcmData()  is seeking");
            av_usleep(1000 * 100);
            continue;
        }


        if (audioDataQueue->getQueueSIze() == 0) {//没有新的数据包,说明在加载中
            LOGE("audioDataQueue->getQueueSIze() == 0");
            if (!playStatus->isLoad) {
                playStatus->isLoad = true;
                callBackToJava->onCallLoad(CHILD_THREAD, true);
            }
            av_usleep(1000 * 100);
            continue;
        } else {
            if (playStatus->isLoad) {
                playStatus->isLoad = false;
                callBackToJava->onCallLoad(CHILD_THREAD, false);
            }
        }

        avPacket = av_packet_alloc();
        if (audioDataQueue->popAvpacket(avPacket) != 0) {
            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = NULL;
            continue;
        }
        pthread_mutex_lock(&codecMutex);
        int ret = avcodec_send_packet(audioCodecContex, avPacket);
        if (ret != 0) {
            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = NULL;
            pthread_mutex_unlock(&codecMutex);
            continue;
        }

        avFrame = av_frame_alloc();
        ret = avcodec_receive_frame(audioCodecContex, avFrame);

        if (ret == 0) {//读取到一个avframe
//            LOGE("读取到一个avFrame");
            /**
             * 有声道数 但是声道布局为0
             * 设置声道布局
             */
            if (avFrame->channels > 0 && avFrame->channel_layout == 0) {
                avFrame->channel_layout = av_get_default_channel_layout(avFrame->channels);

            } else if (avFrame->channels == 0 && avFrame->channel_layout > 0) {
                avFrame->channels = av_get_channel_layout_nb_channels(avFrame->channel_layout);
            }

            //重采样上下文
            SwrContext *swrContext = NULL;

            swrContext = swr_alloc_set_opts(NULL,
                                            AV_CH_LAYOUT_STEREO,
                                            AV_SAMPLE_FMT_S16,
                                            avFrame->sample_rate,
                                            avFrame->channel_layout,
                                            static_cast<AVSampleFormat>(avFrame->format),
                                            avFrame->sample_rate,
                                            NULL, NULL);
            if (!swrContext || swr_init(swrContext) < 0) {
                av_packet_free(&avPacket);
                av_free(avPacket);
                avPacket = NULL;

                av_frame_free(&avFrame);
                av_free(avFrame);
                avFrame = NULL;

                swr_free(&swrContext);
                pthread_mutex_unlock(&codecMutex);
                continue;
            }
            nb = swr_convert(swrContext,
                             &buffer,
                             avFrame->nb_samples,
                             (const uint8_t **) (avFrame->data),
                             avFrame->nb_samples);
            int outChannel = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
            data_size = nb * outChannel * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);


            now_time = avFrame->pts * av_q2d(audioBaseTime);
            if(now_time < clock)
            {
                now_time = clock;
            }
            clock = now_time;

            av_frame_free(&avFrame);
            av_free(avFrame);
            avFrame = NULL;
            swr_free(&swrContext);
            swrContext = NULL;
            pthread_mutex_unlock(&codecMutex);
            break;
        } else { //未读取到avframe

            LOGE("未读取到 avframe");
//            data_size=0;

            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = NULL;

            av_frame_free(&avFrame);
            av_free(avFrame);
            avFrame = NULL;
            pthread_mutex_unlock(&codecMutex);
            continue;
        }
    }

//    LOGE("audioGetPcmData  finished");
    return data_size;
}

void AudioDecodec::pause() {
    (*audioPlayItf)->SetPlayState(audioPlayItf, SL_PLAYSTATE_PAUSED);
}

void AudioDecodec::resume() {
    (*audioPlayItf)->SetPlayState(audioPlayItf, SL_PLAYSTATE_PLAYING);
}

/**
 * SL_API SLresult SLAPIENTRY slCreateEngine(
 *   SLObjectItf             *pEngine,           //对象地址，用于传出对象
 *   SLuint32                numOptions,         //配置参数数量
 *   const SLEngineOption    *pEngineOptions,    //配置参数，为枚举数组
 *   SLuint32                numInterfaces,      //支持的接口数量
 *   const SLInterfaceID     *pInterfaceIds,     //具体的要支持的接口，是枚举的数组
 *   const SLboolean         *pInterfaceRequired //具体的要支持的接口是开放的还是关闭的，也是一个数组，这三个参数长度是一致的
 *   );
 */





int AudioDecodec::getCurrentSampleRateForOpensles(int sample_rate) {

    int rate = 0;
    switch (sample_rate) {
        case 8000:
            rate = SL_SAMPLINGRATE_8;
            break;
        case 11025:
            rate = SL_SAMPLINGRATE_11_025;
            break;
        case 12000:
            rate = SL_SAMPLINGRATE_12;
            break;
        case 16000:
            rate = SL_SAMPLINGRATE_16;
            break;
        case 22050:
            rate = SL_SAMPLINGRATE_22_05;
            break;
        case 24000:
            rate = SL_SAMPLINGRATE_24;
            break;
        case 32000:
            rate = SL_SAMPLINGRATE_32;
            break;
        case 44100:
            rate = SL_SAMPLINGRATE_44_1;
            break;
        case 48000:
            rate = SL_SAMPLINGRATE_48;
            break;
        case 64000:
            rate = SL_SAMPLINGRATE_64;
            break;
        case 88200:
            rate = SL_SAMPLINGRATE_88_2;
            break;
        case 96000:
            rate = SL_SAMPLINGRATE_96;
            break;
        case 192000:
            rate = SL_SAMPLINGRATE_192;
            break;
        default:
            rate = SL_SAMPLINGRATE_44_1;
    }
    return rate;
}

void AudioDecodec::setMute(int mute) {
    LOGE("AudioDecodec::setMute  mute is %d",mute);
    this->mute = mute;

    if(NULL==slMuteSoloItf){
        LOGE("AudioDecodec::setMute slMuteSoloItf is NULL")
        return;;
    }
    switch (mute){
        case 0:
            (*slMuteSoloItf)->SetChannelMute(slMuteSoloItf, 1, false);
            (*slMuteSoloItf)->SetChannelMute(slMuteSoloItf, 0, true);
            break;
        case 1:
            (*slMuteSoloItf)->SetChannelMute(slMuteSoloItf, 1, true);
            (*slMuteSoloItf)->SetChannelMute(slMuteSoloItf, 0, false);
            break;
        case 2:
            (*slMuteSoloItf)->SetChannelMute(slMuteSoloItf, 1, false);
            (*slMuteSoloItf)->SetChannelMute(slMuteSoloItf, 0, false);
            break;
    }
}

void AudioDecodec::setVolume(int percent) {
    volumePercent = percent;
    LOGE("AudioDecodec::setVolume  setVolume is %d",percent);
    if (NULL != slVolumeItf) {
        if (percent > 30) {
            (*slVolumeItf)->SetVolumeLevel(slVolumeItf, (100 - percent) * -20);
        } else if (percent > 25) {
            (*slVolumeItf)->SetVolumeLevel(slVolumeItf, (100 - percent) * -22);
        } else if (percent > 20) {
            (*slVolumeItf)->SetVolumeLevel(slVolumeItf, (100 - percent) * -25);
        } else if (percent > 15) {
            (*slVolumeItf)->SetVolumeLevel(slVolumeItf, (100 - percent) * -28);
        } else if (percent > 10) {
            (*slVolumeItf)->SetVolumeLevel(slVolumeItf, (100 - percent) * -30);
        } else if (percent > 5) {
            (*slVolumeItf)->SetVolumeLevel(slVolumeItf, (100 - percent) * -34);
        } else if (percent > 3) {
            (*slVolumeItf)->SetVolumeLevel(slVolumeItf, (100 - percent) * -37);
        } else if (percent > 0) {
            (*slVolumeItf)->SetVolumeLevel(slVolumeItf, (100 - percent) * -40);
        } else {
            (*slVolumeItf)->SetVolumeLevel(slVolumeItf, (100 - percent) * -100);
        }
    }
}


